import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
from sklearn.impute import SimpleImputer
import seaborn as sns

# 设置图片清晰度
plt.rcParams['figure.dpi'] = 300

# 设置 matplotlib 支持中文，指定支持中文的字体
plt.rcParams['font.sans-serif'] = ['WenQuanYi Zen Hei', 'SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 加载数据集
data_path = r'D:\project\pca\test/winequality-red.csv'
try:
    data = pd.read_csv(data_path, sep=';')
except FileNotFoundError:
    print(f"文件 {data_path} 未找到，请检查路径是否正确。")
    exit(1)

print('数据基本信息：')
data.info()

# 查看数据集行数和列数
rows, columns = data.shape

if rows < 100 and columns < 20:
    # 短表数据（行数少于100且列数少于20）查看全量数据信息
    print('数据全部内容信息：')
    print(data.to_csv(sep='\t', na_rep='nan'))
else:
    # 长表数据查看数据前几行信息
    print('数据前几行内容信息：')
    print(data.head().to_csv(sep='\t', na_rep='nan'))

# 数据预处理部分
# 提取特征变量和目标变量
X = data.drop('quality', axis=1)
y = data['quality']

# 处理缺失值，这里简单地用均值填充
numeric_imputer = SimpleImputer(strategy='mean')
X_imputed = numeric_imputer.fit_transform(X)

# 数据标准化
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X_imputed)

# PCA 降维部分
# 初始化 PCA，先将维度降到 3 维，便于后续选择合适维度
pca = PCA(n_components=3)
X_pca = pca.fit_transform(X_scaled)

# 输出 PCA 结果的基本信息
explained_variance_ratio = pca.explained_variance_ratio_
cumulative_explained_variance = np.cumsum(explained_variance_ratio)
print('解释方差比例:', explained_variance_ratio)
print('累计解释方差比例:', cumulative_explained_variance)

# 选择合适的维度，这里以累计解释方差比例达到 95% 为例
selected_n_components = np.argmax(cumulative_explained_variance >= 0.95) + 1
if selected_n_components > 3:
    selected_n_components = 3
print(f"选择的主成分数量: {selected_n_components}")

# 重新进行 PCA 降维到选择的维度
pca = PCA(n_components=selected_n_components)
X_pca = pca.fit_transform(X_scaled)

# 将降维后的数据转换为 DataFrame，并添加目标变量
pca_df = pd.DataFrame(data=X_pca)
column_names = [f'主成分{i + 1}' for i in range(selected_n_components)]
pca_df.columns = column_names
pca_df['quality'] = y

# 可视化部分
if selected_n_components == 2:
    # 二维降维结果可视化
    plt.figure(figsize=(10, 6))
    sns.scatterplot(x='主成分1', y='主成分2', hue='quality', data=pca_df, palette='viridis')
    plt.title('PCA 降维结果可视化（二维）')
    plt.xlabel('主成分 1')
    plt.ylabel('主成分 2')
    plt.legend()
    plt.show()
elif selected_n_components == 3:
    # 三维降维结果可视化
    from mpl_toolkits.mplot3d import Axes3D
    fig = plt.figure(figsize=(10, 8))
    ax = fig.add_subplot(111, projection='3d')
    scatter = ax.scatter(pca_df['主成分1'], pca_df['主成分2'], pca_df['主成分3'], c=pca_df['quality'], cmap='viridis')
    ax.set_xlabel('主成分 1')
    ax.set_ylabel('主成分 2')
    ax.set_zlabel('主成分 3')
    ax.set_title('PCA 降维结果可视化（三维）')
    fig.colorbar(scatter, ax=ax, label='quality')
    plt.show()

# 进一步分析不同 quality 类别的主成分分布差异，改为绘制点状图
unique_qualities = pca_df['quality'].unique()
for component in column_names:
    plt.figure(figsize=(10, 6))
    for quality in unique_qualities:
        subset = pca_df[pca_df['quality'] == quality]
        plt.scatter(np.repeat(quality, len(subset)), subset[component], alpha=0.5, label=f'Quality {quality}')
    plt.xlabel('Quality')
    plt.xticks(rotation=45)
    plt.ylabel(component)
    plt.title(f'{component} 按 quality 分类的点状图')
    plt.legend()
    plt.show()